// Pedro Ferrer (gth817g)

using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Drawing;
using System.Windows.Forms;



namespace cs2335.CCT
{
    public class ListBox : IComponent, IListSelect
    {
        protected Rectangle mainRectangle = new Rectangle(0, 0, 150, 90);
        protected Rectangle scrollRectangle, upbutton, downbutton, positionbar;
        protected StringFormat labelFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft);
        protected SolidBrush mainBrush = new SolidBrush(Color.White);
        protected SolidBrush scrollBrush = new SolidBrush(Color.LightGray);
        protected SolidBrush triangleBrush = new SolidBrush(Color.Gold);
        protected SolidBrush updownBrush = new SolidBrush(Color.Blue);
        protected SolidBrush positionBrush = new SolidBrush(Color.LightSteelBlue);
        protected SolidBrush selectedBrush = new SolidBrush(Color.Gold);
        protected Font font = new Font("SansSerif", 10);
        protected CCTForm owner;
        protected string text;
        protected bool hasFocus = false;
        protected bool hidden = false;
        protected string name;
        protected ArrayList list;
        protected bool scroll = false;
        protected int top = 0;
        protected int selected=-1;
        protected int domain;

        #region IComponent Members

        #region Properties
        public Point Location
        {
            get { return mainRectangle.Location; }
            set { mainRectangle.Location = value; Invalidate(); }
        }

        public Rectangle Bounds
        {
            get { return mainRectangle; }
            set { mainRectangle = value; Invalidate(); }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public System.Drawing.Font Font
        {
            get { return font; }
            set { font = value; Invalidate(); }
        }

        public string Text
        {
            get { return text; }
            set { text = value; Invalidate(); }
        }

        public CCTForm Owner
        {
            get { return owner; }
            set { owner = value; }
        }

        public Color BackColor
        {
            get { return mainBrush.Color; }
            set { mainBrush.Color = value; Invalidate(); }
        }
        #endregion

        #region Events
        public event EventHandler Click;
        public event EventHandler GotFocus;
        public event EventHandler KeyPress;
        public event EventHandler LostFocus;
        public event EventHandler Paint;
        public event EventHandler KeyDown;
        #endregion

        public ListBox()
        {
            labelFormat.LineAlignment = StringAlignment.Far;
            labelFormat.Alignment = StringAlignment.Far;
            domain = mainRectangle.Height / 15;
            list = new ArrayList();
            list.Add(" ");
        }

        public void Invalidate()
        {
            if (owner != null)
            {
                owner.Invalidate();
            }
        }

        public void Hide()
        {
            hidden = true;
            Invalidate();
        }

        public void Show()
        {
            hidden = false;
            Invalidate();
        }

        public void OnPaint(PaintEventArgs e)
        {
            if (!hidden)
            {
                int y = mainRectangle.Y;
                int x = mainRectangle.X;
                int w = mainRectangle.Width;
                int h = mainRectangle.Height;
                int tempw = w;  //width of generic item rectangles
                domain = mainRectangle.Height / 15;
                Graphics g = e.Graphics;
                
                //setup the scrollbar Rectangles sizes and position
                scrollRectangle = new Rectangle(mainRectangle.Right - 15, mainRectangle.Top, 15, h);
                upbutton = new Rectangle(mainRectangle.Right - 15, mainRectangle.Top, 15, 15);
                downbutton = new Rectangle(mainRectangle.Right - 15, mainRectangle.Bottom-15, 15, 15);
                int pbar = mainRectangle.Top+15+(top*((scrollRectangle.Height-40)/(list.Count-domain)));
                positionbar = new Rectangle(mainRectangle.Right - 15, pbar , 15, 10);

               

                //Drawing 
                g.FillRectangle(mainBrush, mainRectangle);
                
                //Draw Scrollbar
                if (scroll == true || list.Count > domain)
                {
                    //change width of Item rectangles so it does not conflict with scrollbar
                    tempw = w - 15;

                    //draw rectangles
                    g.FillRectangle(scrollBrush, scrollRectangle);
                    g.FillRectangle(updownBrush, upbutton);
                    g.FillRectangle(updownBrush, downbutton);
                    g.FillRectangle(positionBrush, positionbar);
                    
                    // Triangles (point arrays) for up and down buttons
                    Point[] uptriangle = {new Point(upbutton.X+2,upbutton.Y+11),new Point(upbutton.X+8,upbutton.Y+5),
                        new Point(upbutton.X+13,upbutton.Y+11)};
                    Point[] downtriangle = {new Point(downbutton.X+2,downbutton.Y+5),new Point(downbutton.X+8,downbutton.Y+11),
                        new Point(downbutton.X+13,downbutton.Y+5)};
                    
                    //draw triangles
                    g.FillPolygon(triangleBrush, uptriangle);
                    g.DrawPolygon(Pens.Black, uptriangle);
                    g.FillPolygon(triangleBrush, downtriangle);
                    g.DrawPolygon(Pens.Black, downtriangle);

                    //draw borders
                    g.DrawRectangle(Pens.Black, positionbar);
                    g.DrawRectangle(Pens.Black, upbutton);
                    g.DrawRectangle(Pens.Black, downbutton);
                    g.DrawRectangle(Pens.Black, scrollRectangle);
                    g.DrawLine(Pens.Black, positionbar.X + 3, positionbar.Y + 4, positionbar.X + 12, positionbar.Y + 4);
                    g.DrawLine(Pens.Black, positionbar.X + 3, positionbar.Y + 6, positionbar.X + 12, positionbar.Y + 6);
                }

                //Draw Borders
                g.DrawRectangle(Pens.DarkGray, mainRectangle.Left, mainRectangle.Top, mainRectangle.Width, mainRectangle.Height);
                g.DrawRectangle(Pens.Gray, mainRectangle.Left - 1, mainRectangle.Top - 1, mainRectangle.Width + 2, mainRectangle.Height + 2);


                if (hasFocus)
                {
                    if (selected == -1)
                        selected = 0;
                    selectedBrush.Color = Color.Gold;
                    g.DrawRectangle(Pens.LightBlue, mainRectangle.X - 1, mainRectangle.Y - 1, mainRectangle.Width + 2, mainRectangle.Height + 2);
                }
                else
                    selectedBrush.Color = Color.LightGray;
                
                //iterate through the top index item to the last index able to be shown in the list
                for (int index = top; (index - top) < domain && index < list.Count; index++)
                {

                    text = (string)list[index];

                    // generic rectangle for indivdual items
                    RectangleF temp = new RectangleF(x, y + (index - top) * 15, tempw, 15);
                 
                    //if item is selected then fill rectangle with selected color
                    if (index == selected)
                    {
                        
                        g.FillRectangle(selectedBrush, temp);
                        g.DrawString(text, font, Brushes.Black, temp, labelFormat);
                    }

                    else
                    {
                        g.DrawString(text, font, Brushes.Black, temp, labelFormat);
                    }
                }

                

                
                if (Paint != null)
                {
                    Paint(this, e);
                }
            }

        }

        public void OnGotFocus(EventArgs e)
        {
            hasFocus = true;
            if (GotFocus != null)
            {
                GotFocus(this, e);
            }
            owner.Invalidate();
        }

        public void OnLostFocus(EventArgs e)
        {
            hasFocus = false;
            if (LostFocus != null)
            {
                LostFocus(this, e);
            }
            owner.Invalidate();
        }


        public void OnMouseClick(System.Windows.Forms.MouseEventArgs e)
        {

            if (upbutton.Contains(e.X, e.Y))
            {
                if (top > 0)
                {
                    top--;
                    Invalidate();
                }
            }
            else if (downbutton.Contains(e.X, e.Y))
            {
                if (top < list.Count - domain)
                {
                    top++;
                    Invalidate();
                }
            }

            //Determines which item is being selected
            else if (mainRectangle.Contains(e.X+15, e.Y))
            {
                int count = 0;
                int ty = e.Y - mainRectangle.Y;
                while (ty > 15)
                {
                    count++;
                    ty -= 15;
                }
                selected = count + top;
                if (((count + 1) * 15) > mainRectangle.Height)
                {
                    if (top < list.Count - domain)
                    {
                        top++;
                    }
                }

                Invalidate();
                
            }
            
            else if (Click != null)
            {
                Click(this, e);
            }

        }

        // This method is to handle the up and down arrow keys when selecting items
        public void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
    
            if (e.KeyData == Keys.Up)
            {

                if (selected == top)
                {                
                    if (top > 0)
                    {
                        top--;
                        selected--;
                        Invalidate();
                    }
                }
                else
                {
                    selected--;
                    Invalidate();
                }
            }

            if (e.KeyData == Keys.Down)
            {
                if (selected < list.Count-1)
                {
                    if (selected == top + domain - 1)
                    {
                        top++;
                        selected++;
                        Invalidate();
                    }
                    else
                    {
                        selected++;
                        Invalidate();
                    }
                }
            }
            
            else if (KeyDown != null)
            {
                KeyDown(this, e);
            }

       }

        public void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
        {
            if (KeyPress != null)
            {
                KeyPress(this, e);
            }
        }

       

        #endregion

        #region IListSelect Members

        public System.Collections.ArrayList Items
        {
            get { return list; }

            //sets list and sorts it alphabetically 
            set { list = value; list.Sort(); }
        }

        public bool ScrollAlwaysVisable
        {
            get
            {
                return scroll;
            }
            set
            {
                scroll = value;
            }
        }

        public int TopIndex
        {
            get
            {
                return top;
            }
            set
            {
                top = value;
            }
        }

        public void SetSelected(int index, bool value)
        {
            if (value == true)
                selected = index;
            if (value == false)
                selected = -1;
        }
        public int GetSelected()
        {
            return selected;
        }

        #endregion
    }
}


